home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / terminal / qterm-6.0 / qterm-6 / qterm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-14  |  19.9 KB  |  794 lines

  1. #ifndef lint
  2. static char RCSid[] = 
  3. "$Id: qterm.c,v 6.14 1993/06/14 22:24:04 mcooper Exp mcooper $";
  4.  
  5. static char copyright[] =
  6. "@(#) Copyright (c) 1990-1993 Michael A. Cooper.\n\
  7.  All rights reserved.\n";
  8. #endif
  9.  
  10. /*
  11.  * Copyright (c) 1990-1993 Michael A. Cooper.
  12.  * This software may be freely distributed provided it is not sold for 
  13.  * profit and the author is credited appropriately.
  14.  */
  15.  
  16. /*
  17.  * qterm - Query Terminal
  18.  *
  19.  * qterm is used to query a terminal to determine the name of the terminal.
  20.  * This is done by sending a fairly universal string "\33Z" to the terminal,
  21.  * reading in a response, and comparing it against a master table of responses
  22.  * and names.  The "name" printed to standard output should be one found in
  23.  * the termcap(5) database.
  24.  *
  25.  * Putting a line in your ".login" file such as:
  26.  *
  27.  *    setenv TERM `qterm`
  28.  *
  29.  * or the following lines in your ".profile" file:
  30.  *
  31.  *    TERM=`qterm`
  32.  *    export TERM
  33.  *
  34.  * will set your terminal type automagically.
  35.  * 
  36.  * If you add a terminal to the master table, please also send me a copy
  37.  * so that I may put it into my version.
  38.  *
  39.  * Michael A. Cooper
  40.  * mcooper@usc.edu
  41.  */
  42.  
  43. #include "config.h"
  44.  
  45. #include <stdio.h>
  46. #include <ctype.h>
  47. #include <signal.h>
  48. #include <sys/ioctl.h>
  49. #include <setjmp.h>
  50. #include "qterm.h"
  51. #include "version.h"
  52. #include "options.h"
  53.  
  54. int                 Found = FALSE;
  55. int                 ModesSet = FALSE;
  56. jmp_buf             JmpEnv;
  57. char                    *ProgName = NULL;
  58. char                    *TermFile = NULL;
  59. char                  **CommonSeqs = NULL;
  60. char                   *QueryStr = NULL;
  61. struct termtable            *TermTable = NULL;
  62.  
  63. int Debug = FALSE;        /* Debug mode */
  64. int PrVersion = FALSE;        /* Print version */
  65. int UseAltStr = FALSE;        /* Alternate string */
  66. int ToWait = FALSE;        /* Time out wait flag */
  67. int AlwaysSend = FALSE;        /* Intense query mode */
  68. int LongName = FALSE;        /* Print long terminal name */
  69. int SentChars = FALSE;        /* Print strings sent from the terminal */
  70. int WatchChars = FALSE;        /* Watch strings as they are sent and recv. */
  71. int Quiet = FALSE;        /* Quiet mode */
  72. int DoUsrTabFile = FALSE;    /* Use user's own .qtermtab file */
  73. int DoSysTabFile = TRUE;    /* Use the system's qterm tab file */
  74. int ShowReal = FALSE;        /* Show real terminal name */
  75. int TimeOut = TIMEOUT;        /* Wait (timeout) interval */
  76. int TryCommon = FALSE;        /* Try sending common answerback strings */
  77.  
  78. /*
  79.  * Old options should not be visable in help and usage messages.
  80.  */
  81. #ifdef OPT_COMPAT
  82. #define OLD_NoArg    NoArg|ArgHidden
  83. #define OLD_SepArg    SepArg|StickyArg|ArgHidden
  84. #define fFLAG         "-f"
  85. #define FFLAG        "-F"
  86. #endif
  87.  
  88. /*
  89.  * Command line options table.
  90.  */
  91. OptionDescRec opts[] = {
  92. #ifdef OPT_COMPAT
  93.     {"-a",     OLD_NoArg,    OptInt,    (caddr_t) &UseAltStr,        "1",
  94.      (char *)NULL,    "Use alternate query string"},
  95.     {"-s",    OLD_NoArg,    OptInt,    (caddr_t) &SentChars,        "1",
  96.      (char *)NULL,    "Display the characters the terminal sent"},
  97.     {"-t", ArgHidden|OLD_NoArg,    OptInt,    (caddr_t) &SentChars,        "1",
  98.      (char *)NULL,    "Display the characters the terminal sent"},
  99.     {"-I",    OLD_NoArg,    OptInt,    (caddr_t) &AlwaysSend,        "1",
  100.      (char *)NULL,    "Always send the terminal query string"},
  101.     {"-T",    OLD_NoArg,    OptInt,    (caddr_t) &ToWait,        "1",
  102.      (char *)NULL,    "Enable time out wait"},
  103.     {"-S",    OLD_NoArg,    OptInt,    (caddr_t) &WatchChars,        "1",
  104.      (char *)NULL,    "Print strings as they are sent and received"},
  105.     {"-q",    OLD_NoArg,    OptInt,    (caddr_t) &Quiet,        "1",
  106.      (char *)NULL,    "Enable quite mode"},
  107.     {"-f",    OLD_SepArg,    OptStr,    (caddr_t) &TermFile,  fFLAG,
  108.      "<tabfile>",  "Try <tabfile>, then ~/.qtermtab, then system tabfile"},
  109.     {"-F",    OLD_SepArg,    OptStr,    (caddr_t) &TermFile,  FFLAG,
  110.      "<tabfile>",    "Try <tabfile>, then ~/.qtermtab"},
  111.     {"-l",    OLD_NoArg,    OptInt,    (caddr_t) &LongName,        "1",
  112.      (char *)NULL,    "Output only the long (verbose) terminal name"},
  113.     {"-d",     OLD_NoArg,    OptInt,    (caddr_t) &Debug,        "1",
  114.      (char *)NULL,    "Enable debug mode"},
  115.     {"-w",    OLD_SepArg,    OptInt,    (caddr_t) &TimeOut,        __ NULL,
  116.      "<interval>",    "Wait (timeout) period (in seconds)"},
  117. #endif /*OPT_COMPAT*/
  118.     {"+alt",     NoArg,        OptBool, (caddr_t) &UseAltStr,    "1",
  119.      (char *)NULL,    "Use alternate query string"},
  120.     {"-alt",     NoArg,        OptBool, (caddr_t) &UseAltStr,    "0",
  121.      (char *)NULL,    "Don't use alternate query string"},
  122.     {"+always",    NoArg,        OptBool, (caddr_t) &AlwaysSend,    "1",
  123.      (char *)NULL,    "Always send the terminal query string"},
  124.     {"-always",    NoArg,        OptBool, (caddr_t) &AlwaysSend,    "0",
  125.      (char *)NULL,    "Don't always send the terminal query string"},
  126.     {"-file",    SepArg,        OptStr,    (caddr_t) &TermFile,          __ NULL,
  127.      "<tabfile>",   "Use <tabfile> to query terminal"},
  128.     {"+longname",NoArg,        OptBool, (caddr_t) &LongName,        "1",
  129.      (char *)NULL,    "Output only the long (verbose) terminal name"},
  130.     {"-longname",NoArg,        OptBool, (caddr_t) &LongName,        "0",
  131.      (char *)NULL,    "Don't output the long (verbose) terminal name"},
  132.     {"-querystr",SepArg,    OptStr,    (caddr_t) &QueryStr,    __ NULL,
  133.      "<str>",       "Query string to use"},
  134.     {"+quiet",    NoArg,        OptBool, (caddr_t) &Quiet,        "1",
  135.      (char *)NULL,    "Enable quiet mode"},
  136.     {"-quiet",    NoArg,        OptBool, (caddr_t) &Quiet,        "0",
  137.      (char *)NULL,    "Disable quiet mode"},
  138.     {"+real",    NoArg,        OptBool, (caddr_t) &ShowReal,        "1",
  139.      (char *)NULL,    "Determine real name of terminal"},
  140.     {"-real",    NoArg,        OptBool, (caddr_t) &ShowReal,        "0",
  141.      (char *)NULL,    "Determine generic name of terminal"},
  142.     {"+sent",    NoArg,        OptBool, (caddr_t) &SentChars,        "1",
  143.      (char *)NULL,    "Display the characters the terminal sent"},
  144.     {"-sent",    NoArg,        OptBool, (caddr_t) &SentChars,        "0",
  145.      (char *)NULL,    "Don't display the characters the terminal sent"},
  146.     {"+timeout",NoArg,        OptBool, (caddr_t) &ToWait,        "1",
  147.      (char *)NULL,    "Enable time out wait"},
  148.     {"-timeout",NoArg,        OptBool, (caddr_t) &ToWait,        "0",
  149.      (char *)NULL,    "Disable time out wait"},
  150.     {"+trycommon",NoArg,    OptBool, (caddr_t) &TryCommon,        "1",
  151.      (char *)NULL,    "Try sending common answerback sequences"},
  152.     {"-trycommon",NoArg,    OptBool, (caddr_t) &TryCommon,        "0",
  153.      (char *)NULL,    "Disable sending common answerbook sequences"},
  154.     {"+usrtab",    NoArg,        OptBool, (caddr_t) &DoUsrTabFile,    "1",
  155.      (char *)NULL,    "Enable using ~/.qtermtab"},
  156.     {"-usrtab",    NoArg,        OptBool, (caddr_t) &DoUsrTabFile,    "0",
  157.      (char *)NULL,    "Disable using ~/.qtermtab"},
  158.     {"-wait",    SepArg,        OptInt,    (caddr_t) &TimeOut,        __ NULL,
  159.      "<interval>",    "Wait (timeout) period (in seconds)"},
  160.     {"+watch",    NoArg,        OptBool, (caddr_t) &WatchChars,    "1",
  161.      (char *)NULL,    "Watch the characters sent and recieved"},
  162.     {"-watch",    NoArg,        OptBool, (caddr_t) &WatchChars,    "0",
  163.      (char *)NULL,    "Don't watch the characters sent and recieved"},
  164.     {"+systab",    NoArg,        OptBool, (caddr_t) &DoSysTabFile,    "1",
  165.      (char *)NULL,    "Enable using system qtermtab file"},
  166.     {"-systab",    NoArg,        OptBool, (caddr_t) &DoSysTabFile,    "0",
  167.      (char *)NULL,    "Disable using system qtermtab file"},
  168.     {"-version", NoArg,        OptBool,(caddr_t) &PrVersion,        "1",
  169.      (char *)NULL,    "Print version information"},
  170.     {"-debug", ArgHidden|NoArg,    OptInt,    (caddr_t) &Debug,        "1",
  171.      (char *)NULL,    "Enable debug mode"},
  172. };
  173.  
  174. /*
  175.  * Reset terminal and exit with status s.
  176.  */
  177. void Done(s)
  178.     int             s;
  179. {
  180.     ReSetModes();
  181.     exit(s);
  182. }
  183.  
  184. /*
  185.  * Catch kill signals and cleanup.
  186.  */
  187. void Catch(signo)
  188.     int                signo;
  189. {
  190.     dprintf("[ Caught signal %d ]\n", signo);
  191.     Done(2);
  192.     /*NOTREACHED*/
  193. }
  194.  
  195. /*
  196.  * Go here when alarm goes off
  197.  */
  198. void WakeUp()
  199. {
  200.     dprintf("[ WakeUp called ]\n");
  201.     longjmp(JmpEnv, 1);
  202.     dprintf("[ longjmp failed! ]\n");
  203. }
  204.  
  205. /*
  206.  * Config() - Perform configuration operations.
  207.  */
  208. Config(argc, argv)
  209.      int             argc;
  210.      char               **argv;
  211. {
  212.     ProgName = argv[0];
  213.  
  214.     /*
  215.      * Parse command line args
  216.      */
  217.     if (ParseOptions(opts, Num_Opts(opts), argc, argv) < 0)
  218.     Done(1);
  219.     /*NOTREACHED*/
  220.  
  221.     /*
  222.      * Check results of command line parsing and perform any
  223.      * needed post processing.
  224.      */
  225.  
  226.     if (LongName)
  227.     Quiet = TRUE;
  228.  
  229.     if (TimeOut == 0) {
  230.     Error("Alarm (wait) time must be greater than 0.");
  231.     Done(1);
  232.     /*NOTREACHED*/
  233.     }
  234.  
  235. #if    defined(OPT_COMPAT)
  236.     /*
  237.      * Kludgy stuff to be backwards compatable for command line options.
  238.      */
  239.     if (TermFile) {
  240.     if (strcmp(TermFile, fFLAG) == 0) {
  241.         DoUsrTabFile = TRUE;
  242.         DoSysTabFile = TRUE;
  243.         TermFile = NULL;
  244.     } else if (strcmp(TermFile, FFLAG) == 0) {
  245.         DoUsrTabFile = TRUE;
  246.         DoSysTabFile = FALSE;
  247.         TermFile = NULL;
  248.     }
  249.     }
  250. #endif /*OPT_COMPAT*/
  251.  
  252.     dprintf("[ %s debug mode enabled ]\n\n", ProgName);
  253. }
  254.  
  255. /*
  256.  * Set signal catches and terminal modes
  257.  */
  258. SetModes()
  259. {
  260.     if (!isatty(0)) {
  261.     Error("This program can only be run on a tty device.");
  262.     Done(0);
  263.     /*NOTREACHED*/
  264.     }
  265.     
  266.     /*
  267.      * Set output buffers
  268.      */
  269.     setbuf(stdout, (char *)0);
  270.     if (Debug)
  271.     setbuf(stderr, (char *)0);
  272.     
  273.     /*
  274.      * Cleanup terminal modes & such if we are killed
  275.      */
  276.     SetupSignals(Catch);
  277.     
  278.     /*
  279.      * Set terminal modes
  280.      */
  281.     if (SetTtyModes() == 0)
  282.     ModesSet = TRUE;
  283. }
  284.  
  285. /*
  286.  * Reset terminal modes
  287.  */
  288. ReSetModes()
  289. {
  290.     dprintf("[ ReSetModes called - %s ]\n", 
  291.         (ModesSet) ? "ModesSet" : "Modes not set");
  292.     if (ModesSet)
  293.     UnSetTtyModes();
  294. }
  295.  
  296. /*
  297.  * Print a message since we didn't recognize this terminal.
  298.  */
  299. void NotRecognized()
  300. {
  301.     char                *envterm;
  302.     
  303.     if ((envterm = getenv("TERM")) == NULL)
  304.     envterm = "dumb";
  305.     
  306.     if (!Quiet)
  307.     (void) fprintf(stderr, 
  308.                "Terminal NOT recognized - defaults to \"%s\".\r\n",
  309.                envterm);
  310.     
  311.     puts(envterm);
  312. }
  313.  
  314. /*
  315.  * Decode - print str in a readable fashion
  316.  */
  317. char *Decode(str)
  318.     char                *str;
  319. {
  320.     register int         len;
  321.     static char         buf[BUFSIZ];
  322.     char             tmp[10];
  323.     
  324.     if (!str)
  325.     return("(null)");
  326.     
  327.     buf[0] = (char) NULL;
  328.     while (*str) {
  329.     if (*str == ESC)
  330.         (void) strcat(buf, "<esc> ");
  331.     else if ((*str <= 33) || (*str >= 127)) {
  332.         (void) sprintf(tmp,"\\%#o ", (unsigned) *str);
  333.         (void) strcat(buf, tmp);
  334.     } else {
  335.         (void) sprintf(tmp, "%c ", *str);
  336.         (void) strcat(buf, tmp);
  337.     }
  338.     ++str;
  339.     }
  340.     
  341.     len = strlen(buf);
  342.     if (len && buf[len - 1] == ' ')
  343.     buf[len - 1] = (char) NULL;
  344.     
  345.     return(buf);
  346. }
  347.  
  348. /*
  349.  * Print info about terminal structure termtable.
  350.  */
  351. void PrInfo(termtable, recvstr)
  352.     struct termtable            *termtable;
  353.     char               *recvstr;
  354. {
  355.     int             len = 0;
  356.     char               *termname = NULL;
  357.     
  358.     if (Debug || SentChars) {
  359.     len = strlen(recvstr);
  360.     (void) fprintf(stderr, "%s received %d character%s:", 
  361.                ProgName, len, (len == 1) ? "" : "s");
  362.     (void) fprintf(stderr, " %s\r\n", Decode(recvstr));
  363.     }
  364.  
  365.     if (ShowReal && (strcmp(termtable->qt_ntermname, "-") != 0))
  366.     termname = termtable->qt_ntermname;
  367.     else
  368.     termname = termtable->qt_termname;
  369.  
  370.     if (!Quiet) {
  371.     (void) fprintf(stderr, "Terminal recognized as %s", termname);
  372.     if (termtable->qt_fullname && termtable->qt_fullname[0])
  373.         (void) fprintf(stderr, " (%s)\r\n", termtable->qt_fullname);
  374.     else
  375.         (void) fprintf(stderr, "\r\n");
  376.     }
  377.     
  378.     if (LongName) {
  379.     if (termtable->qt_fullname && termtable->qt_fullname[0])
  380.         (void) printf("%s\n", termtable->qt_fullname);
  381.     else
  382.         Error("No full terminal name for %s.", termname);
  383.     } else
  384.     (void) printf("%s\n", termname);
  385. }
  386.  
  387. /*
  388.  * FindTermTab - actually compare what we received against the table.
  389.  */
  390. struct termtable *FindTermTab(str, primett)
  391.     char                *str;
  392.     struct termtable           *primett;
  393. {
  394.     register struct termtable  *tp;
  395.     static char         buff[BUFSIZ];
  396.  
  397.     dprintf(" FindTermTab: %s \tPrime = '%s'\n", 
  398.         (str && str[0]) ? Decode(str) : "nothing",
  399.         (primett) ? primett->qt_ntermname : "<none>");
  400.  
  401.     AlarmOff();
  402.     
  403.     if (!str || !*str)
  404.     return((struct termtable *)NULL);
  405.     
  406.     for (tp = TermTable; tp != NULL; tp = tp->nxt) {
  407.     /*
  408.      * If a primary termtab entry was given, then we
  409.      * want to only check secondary entries whose primary
  410.      * terminal name matches the primary's "next" name.
  411.      */
  412.     if (primett && (tp->qt_etype != ET_SECONDARY ||
  413.             strcmp(primett->qt_ntermname, tp->qt_termname)))
  414.         continue;
  415.  
  416.     dprintf("  with %s \t('%s' '%s')", 
  417.         Decode(tp->qt_recvstr), 
  418.         A(tp->qt_termname), A(tp->qt_ntermname));
  419.  
  420.     (void) sprintf(buff, "^%s$", tp->qt_recvstr);
  421.  
  422.     if (strcmp(tp->qt_recvstr, str) == 0 || RegExMatch(buff, str) > 0) {
  423.         Found = TRUE;
  424.         dprintf("\tMATCHED\n");
  425.         return(tp);
  426.     } else
  427.         dprintf("\tno match\n");
  428.     }
  429.     Found = FALSE;
  430.  
  431.     return((struct termtable *)NULL);
  432. }
  433.  
  434. /*
  435.  * GetChar - read in a character at a time.
  436.  */
  437. char GetChar()
  438. {
  439.     char             c;
  440.     
  441.     (void) read(fileno(stdin), &c, 1);
  442.     
  443.     return(c & CHAR_MASK);
  444. }
  445.  
  446. /*
  447.  * Listen for a response.
  448.  */
  449. char *InputListen(termtab)
  450.     struct termtable            *termtab;
  451. {
  452.     register int        i = 0;
  453.     register int        len = 0;
  454.     register char         c;
  455.     char             end;
  456.     static char            recvbuff[RECVSIZE];
  457.     
  458.     AlarmOff();
  459.     recvbuff[0] = (char) NULL;
  460.  
  461.     if (termtab && termtab->qt_recvstr)
  462.     len = strlen(termtab->qt_recvstr);
  463.  
  464.     if (len)
  465.     end = termtab->qt_recvstr[len - 1];
  466.     else
  467.     end = 'c'; /* Fairly standard ANSI default */
  468.     
  469.     if (termtab)
  470.     dprintf("\nlisten for %s\t [ len = %d, end = `%c' ]\n", 
  471.         Decode(termtab->qt_recvstr), len, end);
  472.     else
  473.     dprintf("\n[ listen for response ]\n");
  474.  
  475.     /*
  476.      * Read in remaining response.  Loop until ending character
  477.      * is received or until alarm goes off.  If ToWait is set,
  478.      * then let alarm go off.
  479.      */
  480.     for (i = 0, c = -1; (!ToWait && (c != end)) || ToWait; ) {
  481.     if (setjmp(JmpEnv))  {
  482.         /*
  483.          * Alarm went off
  484.          */
  485.         if (Found)
  486.         Done(0);
  487.             /*NOTREACHED*/
  488.         (void) fflush(stdin);
  489.         (void) fflush(stdout);
  490.         (void) fflush(stderr);
  491.         recvbuff[i] = (char) NULL;
  492.         return((recvbuff[0]) ? recvbuff : (char *)NULL);
  493.     }
  494.  
  495.     AlarmOn(TimeOut, WakeUp);
  496.     c = GetChar();
  497.     AlarmOff();
  498.  
  499.     recvbuff[i++] = c;
  500.     }
  501.     recvbuff[i] = (char) NULL;
  502.     
  503.     dprintf("[ listen done.  read %d chars ]\n\n", i);
  504.  
  505.     return((recvbuff[0]) ? recvbuff : (char *)NULL);
  506. }
  507.  
  508. /*
  509.  * Process entries in the termtable.
  510.  */
  511. void ProcTable(termtab, primett, etype)
  512.     struct termtable            *termtab;
  513.     struct termtable            *primett;
  514.     int                etype;
  515. {
  516.     static struct termtable    *lastt;
  517.     register struct termtable  *tptr;
  518.     register struct termtable  *tp;
  519.     char               *recvstr;
  520.     char               *querystr = NULL;
  521.     static char               *lastquerystr = NULL;
  522.     
  523.     dprintf("\n[ Processing entries:  Prime = '%s' etype = %d ] \n",
  524.         (primett) ? primett->qt_ntermname : "<none>", etype);
  525.  
  526.     Found = FALSE;
  527.  
  528.     for (tptr = termtab; tptr; tptr = tptr->nxt) {
  529.     if (tptr->qt_etype != ET_OLDSTYLE && tptr->qt_etype != etype)
  530.         continue;
  531.  
  532.     /*
  533.      * If a primary termtab entry was given, and it's real term name
  534.      * does not match the secondary's generic name, continue on.
  535.      */
  536.     if (primett && strcmp(primett->qt_ntermname, tptr->qt_termname))
  537.         continue;
  538.  
  539.     if (QueryStr)
  540.         querystr = QueryStr;
  541.     else
  542.         querystr = tptr->qt_sendstr;
  543.  
  544.     /*
  545.      * If this is our first time or the sendstr is the same as
  546.      * last time, don't send it again.
  547.      */
  548.     if (AlwaysSend  || lastt == NULL || 
  549.         strcmp(querystr, lastquerystr) != 0) {
  550.  
  551.         if (WatchChars)
  552.         (void) printf("\tSend: %s\r\n", Decode(querystr));
  553.  
  554.         (void) fflush(stdin);
  555.         (void) fprintf(stderr, "%s", querystr);
  556.         (void) fflush(stderr);
  557.         
  558.         lastt = tptr;
  559.         lastquerystr = querystr;
  560.         recvstr = InputListen(tptr);
  561.         
  562.         if (WatchChars)
  563.         (void) printf("\tRead: %s\t\t[ length = %d ]\r\n", 
  564.                   Decode(recvstr), 
  565.                   (recvstr) ? strlen(recvstr) : 0);
  566.     }
  567.  
  568.     if (tp = FindTermTab(recvstr, primett)) {
  569.         /*
  570.          * We found an entry that matched.
  571.          *
  572.          * If the user wants the real terminal name and we 
  573.          * just did all the primary names, look for a secondary
  574.          * name.
  575.          */
  576.         if (tp->qt_etype != ET_OLDSTYLE && etype == ET_PRIMARY &&
  577.         ShowReal && strcmp(tp->qt_ntermname, "-")) {
  578.  
  579.         dprintf("[ Look for real name of '%s' ]\n", tp->qt_termname);
  580.         ProcTable(termtab, tp, ET_SECONDARY);
  581.         dprintf("[ Cannot find real name of '%s' ]\n", 
  582.             tp->qt_termname);
  583.         }
  584.  
  585.         PrInfo(tp, recvstr);
  586.         Done(0);
  587.         /*NOTREACHED*/
  588.     }
  589.  
  590.     lastt = tptr;
  591.     }
  592. }
  593.  
  594. /*
  595.  * Process common send sequences
  596.  */
  597. void ProcCommon(termtab)
  598.     struct termtable           *termtab;
  599. {
  600.     register struct termtable  *tp;
  601.     register char          **cpp;
  602.     char               *recvstr;
  603.  
  604.     dprintf("[ Proccess Common Sequences ]\n");
  605.  
  606.     for (cpp = CommonSeqs; cpp && *cpp; ++cpp) {
  607.     if (WatchChars)
  608.         (void) printf("Trying   %s\r\n", Decode(*cpp));
  609.  
  610.     (void) fflush(stdin);
  611.     (void) fprintf(stderr, "%s", FixCntrl(*cpp));
  612.     (void) fflush(stderr);
  613.  
  614.     recvstr = InputListen((struct termtable *)NULL);
  615.  
  616.     if (WatchChars && recvstr)
  617.         (void) printf("Recieved %s\r\n", Decode(recvstr));
  618.  
  619.     if (recvstr) {
  620.         if (tp = FindTermTab(recvstr, (struct termtab *)NULL))
  621.         PrInfo(tp, recvstr);
  622.         else
  623.         NotRecognized();
  624.         Done(0);
  625.         /*NOTREACHED*/
  626.     }
  627.     }
  628.  
  629.     NotRecognized();
  630.     Done(2);
  631.     /*NOTREACHED*/
  632. }
  633.  
  634. /*
  635.  * Match a character.  Each element of "list" is compared to
  636.  * character "c".  If it matches, return TRUE.  If no matches
  637.  * are found, return FALSE.
  638.  */
  639. static int match_char(list, c)
  640.     char                *list;
  641.     int             c;
  642. {
  643.     register char            *s;
  644.  
  645.     for (s = list; s && *s; ++s) {
  646.     if (*s == (char) c)
  647.         return(TRUE);
  648.     }
  649.  
  650.     return(FALSE);
  651. }
  652.  
  653. /*
  654.  * Parse a "string" seperated by "sep" into a null terminate
  655.  * "array".  The array "sep" should be a null terminated list
  656.  * of characters that specify a seperator between arguments.
  657.  * Returns the number of arguments placed into "array".
  658.  */
  659. int StrToArgs(string, array, sep)
  660.      char                *string;
  661.      char              ***array;
  662.      char                *sep;
  663. {
  664.     register int         argc, x;
  665.     register char            *p;
  666.     char                *start, *end;
  667.     char               **argv;
  668.  
  669.     if (!string || !array || !sep)
  670.     return(-1);
  671.  
  672.     /*
  673.      * Count arguments
  674.      */
  675.     for (argc = 0, p = string; p && *p; ++argc) {
  676.     while (p && *p && match_char(sep, *p))    /* skip leading seperators */
  677.         ++p;
  678.  
  679.     while (p && *p && !match_char(sep, *p))    /* skip over argument */
  680.         ++p;
  681.     }
  682.  
  683.     /*
  684.      * If we've allocated memory before for this buffer, free it now.
  685.      */
  686.     argv = *array;
  687.     if (argv != NULL) {
  688.     for (x = 0; argv[x] != NULL; ++x)
  689.         (void) free(argv[x]);
  690.     (void) free(argv);
  691.     argv = NULL;
  692.     }
  693.  
  694.     /*
  695.      * Allocate enough memory for each argument + NULL terminator
  696.      */
  697.     argv = (char **) xmalloc((argc + 1) * sizeof(char *));
  698.  
  699.     /*
  700.      * Actually parse the string and place arguments in buffer.
  701.      */
  702.     for (x = 0, p = string; x < argc; ++x) {
  703.     while (p && *p && match_char(sep, *p))    /* skip leading seperators */
  704.         ++p;
  705.  
  706.     start = p;                /* mark start of argument */
  707.     while (p && *p && !match_char(sep, *p))    /* skip over argument */
  708.         ++p;
  709.     end = p;                /* mark end of argument */
  710.  
  711.     /* Save argument */
  712.     argv[x] = (char *) xmalloc((end-start)+1);
  713.     strncpy(argv[x], start, end-start);
  714.     argv[x][end-start] = (char) NULL;
  715.     }
  716.     argv[argc] = NULL;
  717.     *array = argv;
  718.  
  719.     return(argc);
  720. }
  721.  
  722. /*
  723.  * Initialize things.
  724.  */
  725. Init(argc, argv)
  726.      int             argc;
  727.      char               **argv;
  728. {
  729.     static char           **av = NULL;
  730.     static char              **tav = NULL;
  731.     register int         x;
  732.     char                *envstr;
  733.     int             ac;
  734.  
  735.     /*
  736.      * Get options from $QTERMOPTIONS
  737.      */
  738.     if ((envstr = getenv("QTERMOPTIONS")) != NULL)
  739.     if ((ac = StrToArgs(envstr, &av, " \t")) > 0) {
  740.         tav = (char **) xmalloc((sizeof(char *) * ac) + 2);
  741.         tav[0] = argv[0];
  742.         for (x = 0; x < ac; ++x)
  743.         tav[x+1] = av[x];
  744.         Config(ac+1, tav);
  745.     }
  746.  
  747.     /*
  748.      * Now try command line options
  749.      */
  750.     Config(argc, argv);
  751.  
  752.     if (Debug)
  753.     ++WatchChars;
  754. }
  755.  
  756. /*
  757.  * Print version info
  758.  */
  759. void PrintVersion()
  760. {
  761.     printf("Qterm Version %s", VERSION);
  762.     if (PATCHLEVEL)
  763.     printf(".%d", PATCHLEVEL);
  764.     printf(" - Release %s, Patch level %d\n", VERSION, PATCHLEVEL);
  765. }
  766.  
  767. /*
  768.  * Where it all begins
  769.  */
  770. main(argc, argv)
  771.      int             argc;
  772.      char               **argv;
  773. {
  774.     Init(argc, argv);
  775.  
  776.     if (PrVersion) {
  777.     PrintVersion();
  778.     exit(0);
  779.     }
  780.  
  781.     SetModes();
  782.     MakeTable();
  783.     if (TryCommon)
  784.     ProcCommon(TermTable);
  785.     else
  786.     ProcTable(TermTable, (struct termtable *)NULL, ET_PRIMARY);
  787.     ReSetModes();
  788.     
  789.     if (!Found)
  790.     NotRecognized();
  791.  
  792.     exit((Found) ? 0 : 2);
  793. }
  794.